Java的學習初期,我曾經無法理解人稱 Java 8 三大神器之一的stream()魅力,覺得用迴圈與if判斷的寫法才是最好用的,但隨著開發的熟悉度上升,這些寫法也逐漸融入我日常開發的方法,這次就來看一些Java的 Functional API吧。本次以Optional為主進行介紹。
在Java的世界中,NullPointerException一直是開發者痛恨的狀況,主要原因有二:
這時可以考慮使用的工具是Java Optional,他可以幫助開發者解決惱人的NPE問題。基本的使用方法如下:
Optional<Student> student = Optional.of(studentService.findByName(name));
Optional<Student> studentNullable = Optional.ofNullable(studentService.findByName(name));
if (studentNullable.isPresent()) {
Student s = studentNullable.get();
}
前兩行的功能是建構一個Optional物件,主要的差別是 Optional.of() 不接受內容為Null物件,如果內容為Null會直接爆出NullPointerException,這麼做的好處是避免造成一個Null到處傳遞,最後在一個你想都想不到的地方跑出NPE。
Optional.ofNullable()則是一個可接受Null的物件。第三行則是判斷是否為Null,第四行判斷如果不是Null的話就取值。
在這邊先提醒一下,isPresent()用來判斷的只是Null,並不像其他isEmpty()之類的,可以判斷空物件、空字串之類的,isPresent()就只是拿來處理Null。
我知道你應該是這麼想的:如果Optional只能拿來判斷Null,我還不如直接寫 ≠ null,裡面還可以做更多事,要取得內容還得先呼叫.get(),真的很麻煩。
我知道你已經想轉台了。但請先等等,我一開始也是這麼覺得的,但後來我發覺Optional的功能其實沒有那麼糟。看看Optional是怎麼處理例外的吧。
Student studentNullable = Optional.ofNullable(studentService.findByName(name))
.orElse(new Student());
Student studentNullable2 = Optional.ofNullable(st)
.orElseGet( () -> new Student(0,"Admin",0));
Student studentNullable3 = Optional.ofNullable(studentNullable)
.orElseThrow(() -> new IllegalArgumentException("Student not exist"));
以下展現了三種Student物件處理Null的方法,Optional允許我們只要在一個鏈狀結構中處理Null就可以不必包Optional,省去了.get()的方法。
第一行是用來判斷內容是否為Null,若是Null則回傳一個空的新物件。
第二行與第一行類似,只是第二行使用了Java 的Lambda語法去建立一個新物件並回傳到studentNullable2
第三行則是最常用的,只要為Null當下就拋出NPE,完全零容忍,像是這邊就拋出一個自定義的例外,告訴我們說該Student不存在。
還覺得不夠嗎?那是時候來介紹另外一個API - stream()了。
stream()是Java工程師用來處理複雜邏輯處理的一個工具,Optional的另一個大優勢就是可以接上它,因此你可以寫出更多的功能,比方說以下例子。
Optional.ofNullable(st1)
.filter(student -> student.getAge()> 18)
.filter(student -> student.getName().equals("Joe"))
.isPresent(); // 過濾資料是否符合18以上 名字叫做Joe的人
Family motherName = Optional.ofNullable(st2)
.map(s -> s.getFamily())
.filter( f -> f.getMotherName().equals("Mary"))
.orElseThrow(() -> new IllegalObjectStatusException("NotFound"));
// 找出學生家庭的母親姓名,如果是Mary就回傳Family 否則跳出例外
另外值得一提的是,在第二個例子中假設Family類別為null時,也不會回報NPE,則是遵循撰寫的Optional語法執行orElseThrow()拋出自定義例外。
以上就是Optional與Stream的小小分享,明天見了。
參考資料:
https://openhome.cc/zh-tw/java/functional-api/stream/